GUI系统之SurfaceFlinger HAL层(一)

SurfaceFlinger是GUI系统的核心,本篇将以自底向上的方式对其展开介绍。

硬件层面

Linux 内核提供了统一的famebuffer显示驱动,设备节点/dev/graphics/fb* 或者 /dev/fb*,fb0是第一个显示屏。

HAL层面

HAL即硬件抽象层,Android的各个子系统通常不会直接使用内核驱动,而是由HAL层简介引用底层架构。Android的HAL层提供了Gralloc,包括了fb和gralloc两个设备。前者负责打开内核中的framebuffer,初始化配置;后者则管理帧缓冲去的分配和释放。

在HAL层中还有一个重要的模块 “Composer”,它为厂商自定制“UI合成”提供了接口。Composer的直接使用者是SurfaceFlinger中的HWComposer

Gralloc模块

下面我们就从HAL层来看看Gralloc的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
hardware\libhardware\include\hardware\gralloc.h
typedef struct gralloc_module_t {
struct hw_module_t common;//每个硬件模块对应的结构都需要hw_module_t这个抽象模块
int (*registerBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);

int (*unregisterBuffer)(struct gralloc_module_t const* module,
buffer_handle_t handle);

int (*lock)(struct gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
int (*unlock)(struct gralloc_module_t const* module,
buffer_handle_t handle);
……………
void* reserved_proc[3];
} gralloc_module_t;

对于以上的结构体需要注意的是:
1.每一个硬件都有其对应的模块结构,并且该结构的第一个成员必须为hw_module_t结构,该结构是HAL层对硬件的统一抽象。所以每一个硬件模块都要对应一个hw_module_t结构,并且名称必须为HAL_MODULE_INFO_SYM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hardware\libhardware\include\hardware\hardware.h
typedef struct hw_module_t {
uint32_t tag;
uint16_t module_api_version;//version_major
uint16_t hal_api_version;//version_minor
const char *id;
const char *name;
const char *author;
struct hw_module_methods_t* methods;

} hw_module_t;

typedef struct hw_module_methods_t {
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;

hw_module_t结构用来描述硬件模块的基本信息,如当前的版本,模块Id以及硬件模块对应的打开方法。

Gralloc模块负责管理gralloc设备和fb设备,它是处于HAL层的,向上提供了这个两个设备的功能。其中最主要的两个接口分别为gralloc_device_open和gralloc_alloc。
我们先看gralloc_device_open,这个方法负责打开gralloc或者fb设备的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//gralloc模块的打开设备方法
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {//打开GPU
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));

/* initialize our state here */
memset(dev, 0, sizeof(*dev));

/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;

dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;

*device = &dev->device.common;
status = 0;
} else {//打开fb设备
status = fb_device_open(module, name, device);
}
return status;
}

参数name指定了要打开的模块,Name为GRALLOC_HARDWARE_GPU0说明打开的是GPU,否则打开fb设备。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//对外的分配缓冲区的方法
static int gralloc_alloc(alloc_device_t* dev,
int width, int height, int format, int usage,
buffer_handle_t* pHandle, int* pStride)
{
if (!pHandle || !pStride)
return -EINVAL;

int bytesPerPixel = 0;
switch (format) {//指定的缓冲区像素格式
case HAL_PIXEL_FORMAT_RGBA_FP16:
bytesPerPixel = 8;
break;
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
bytesPerPixel = 4;
break;
case HAL_PIXEL_FORMAT_RGB_888:
bytesPerPixel = 3;
break;
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RAW16:
bytesPerPixel = 2;
break;
default:
return -EINVAL;
}

const size_t tileWidth = 2;
const size_t tileHeight = 2;

size_t stride = align(width, tileWidth);
size_t size = align(height, tileHeight) * stride * bytesPerPixel + 4;

int err;
if (usage & GRALLOC_USAGE_HW_FB) {//在FB设备中分配帧缓冲区
err = gralloc_alloc_framebuffer(dev, size, usage, pHandle);
} else {//在内存中分配图形缓冲区
err = gralloc_alloc_buffer(dev, size, usage, pHandle);
}

if (err < 0) {
return err;
}

*pStride = stride;
return 0;
}

另一个方法gralloc_alloc 负责为上层分配缓冲区,注意这里的缓冲区既可以是内存缓冲区,也可以是fb的帧缓冲区。这分别是通过gralloc_alloc_buffer 和 gralloc_alloc_framebuffer来实现的。在内存中创建缓冲区是基于asheme的方式来创建一块匿名共享内存来作为缓冲区的,而如果是从fb中分配则只需要将fb的帧缓冲区映射到当前进程来即可。具体可以参见famebuffer.cpp中的mapFrameBufferLocked方法。

关于fb设备 其最重要的功能是将上层缓冲区的内容通过交换显示在屏幕上,这个功能是通过fb_post来实现的,在这之前我们看看如何打开fb设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//打开fb设备 这个方法通过HAL层的Gralloc模块提供给上层接口
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {//打开的是Fb设备
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));//分配fb_context_t 结构
memset(dev, 0, sizeof(*dev));

/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;//设置设备post回调接口,这个接口将缓冲区的内容显示在屏幕上
dev->device.setUpdateRect = 0;

private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);//对fb设备进行映射 其实是调用mapFrameBufferLocked
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
int format = (m->info.bits_per_pixel == 32)
? (m->info.red.offset ? HAL_PIXEL_FORMAT_BGRA_8888 : HAL_PIXEL_FORMAT_RGBX_8888)
: HAL_PIXEL_FORMAT_RGB_565;
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//将缓冲区的内容显示在屏幕上
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;

fb_context_t* ctx = (fb_context_t*)dev;

private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);

if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { //如果缓冲区是来自于fb设备的帧缓冲区
const size_t offset = hnd->base - m->framebuffer->base;
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;//直接调整y方向的分辨率偏移既可,不需要做任何拷贝
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {//通过FBIOPUT_VSCREENINFO命令
ALOGE("FBIOPUT_VSCREENINFO failed"); //显示在屏幕上
m->base.unlock(&m->base, buffer);
return -errno;
}
m->currentBuffer = buffer;

} else { //否则是来自内存的缓冲区
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy

void* fb_vaddr;
void* buffer_vaddr;

m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);//对帧缓冲区加锁

m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);//对内存缓冲区加锁

memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);//需要将内存的缓冲区拷贝到fb的帧 缓冲中

m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}

好了,对于HAL层的模块分析就到这里了,下篇我们介绍下VSYNC信号相关的内容。

参考

http://blog.csdn.net/luoshengyang/article/details/7747932

坚持原创技术分享,您的支持将鼓励我继续创作!